using ExamRoomAllocationManagement.Dao;
using System.Collections.Generic;
using System.Text.Json;
using Xmu.Stores.Models;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using System.Drawing.Printing;


namespace Xmu.ExamRoomAllocationManagement.Services
{
    public class AllocationService : ISingletonDependency
    {
        private IServiceProvider serviceProvider;
        private Repositories repo;
        private AutoAllocationService autoAllocationService;
        public AllocationService(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
            repo = serviceProvider.CreateScope().ServiceProvider.GetRequiredService<Repositories>();
        }
        public int GetPageNum(int pageSize)
        {
            int size = repo.ExamRoomAllocations.Count();
            return (size % pageSize == 0) ? (size / pageSize) : (size / pageSize + 1);
        }

        public void BuildAllocation(ExamRoomAllocation allocation)
        {
            allocation.Exam = repo.Exams.FirstOrDefault(exam => exam.ExamId == allocation.ExamId);
            allocation.ExamRoom = repo.ExamRooms.FirstOrDefault(room => room.ID == allocation.ExamRoomId);
            allocation.Registration1 = repo.Registrations.FirstOrDefault(reg => reg.ID == allocation.Registration1ID);
            allocation.Registration2 = repo.Registrations.FirstOrDefault(reg => reg.ID == allocation.Registration2ID);
        }

        public (object allocations, object pageNum, object msg) GetAllocations(int pageIndex, int pageSize)
        {
            List<ExamRoomAllocation> res = repo.ExamRoomAllocations.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            foreach (ExamRoomAllocation allocation in res)
            {
                BuildAllocation(allocation);
            }
            return (repo.ExamRoomAllocations.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(), GetPageNum(pageSize), "ok");
        }

        public (object allocations, object msg) GetEveryAllocations()
        {
            List<ExamRoomAllocation> examRoomAllocations = repo.ExamRoomAllocations.ToList();
            foreach(ExamRoomAllocation allocation in examRoomAllocations)
            {
                BuildAllocation(allocation);
            }
            return (examRoomAllocations, "ok");
        }

        public (object allocations, object pageNum, object msg) GetAllocationsByStatus(AllocationStatus status, int pageIndex, int pageSize)
        {
            List<ExamRoomAllocation> res = repo.ExamRoomAllocations
                .Where(allocation => allocation.AllocationStatus.Equals(status))
                .Skip((pageIndex - 1) * pageIndex).Take(pageSize)
                .ToList();
            foreach (ExamRoomAllocation allocation in res)
            {
                BuildAllocation(allocation);
            }

            int pageNum = GetPageNum(pageSize);
            return (res, pageNum, "ok");
        }


        public (object allocation, object msg) GetAllocation(Guid roomid)
        {   
            ExamRoomAllocation? allocation = repo.ExamRoomAllocations.FirstOrDefault(allocation => allocation.ExamRoomId == roomid);
            if(allocation != null)
            {
                BuildAllocation(allocation);
            }
            return (allocation, "ok");
        }

        public (bool success, string msg) CalcStatus(ExamRoomAllocation allocation)
        {
            if (allocation == null)
            {
                Console.WriteLine("CalcStatus:allocation is null");
            }
            if (!CheckDepartmentDiff(allocation))
            {
                allocation.AllocationStatus = AllocationStatus.UnableToAllocate;
                repo.DbContex.SaveChanges();
                return (false, "部门相同");
            }
            if (!CheckNotBothNew(allocation))
            {
                allocation.AllocationStatus = AllocationStatus.UnableToAllocate;
                repo.DbContex.SaveChanges();
                return (false, "都是新老师");
            }
            if (!CheckGenderDiff(allocation))
            {
                allocation.AllocationStatus = AllocationStatus.AllocationWithIssues;
                repo.DbContex.SaveChanges();
                return (false, "性别相同");
            }
            if (!CheckParticipatedDiff(allocation))
            {
                allocation.AllocationStatus = AllocationStatus.AllocationWithIssues;
                repo.DbContex.SaveChanges();
                return (false, "不满足老带新");
            }
            return (true, "ok");
        }

        public bool CheckGenderDiff(ExamRoomAllocation allocation)
        {
            return allocation.Registration1.Gender != allocation.Registration2.Gender;
        }

        public bool CheckDepartmentDiff(ExamRoomAllocation allocation)
        {
            return allocation.Registration1.Workplace != allocation.Registration2.Workplace;
        }

        public bool CheckParticipatedDiff(ExamRoomAllocation allocation)
        {
            return allocation.Registration1.ParticipatedLastYear != allocation.Registration2.ParticipatedLastYear;
        }
        public bool CheckNotBothNew(ExamRoomAllocation allocation)
        {
            return allocation.Registration1.ParticipatedLastYear || allocation.Registration2.ParticipatedLastYear;
        }

        internal (bool success, string msg) AdjustAllocation(Guid regId1, Guid regId2)
        {
            Registration? reg1 = repo.Registrations.FirstOrDefault(reg => reg.ID == regId1);
            Registration? reg2 = repo.Registrations.FirstOrDefault(reg => reg.ID == regId2);
            if (reg1 == null || reg2 == null)
            {
                return (false, "registration not exist!");
            }


            ExamRoomAllocation? era1 = repo.ExamRoomAllocations.FirstOrDefault(era => era.Registration1ID == regId1);
            if (era1 != null)
            {
                era1.Registration1 = reg2;
                era1.Registration1ID = regId2;
            }
            else
            {
                era1 = repo.ExamRoomAllocations.FirstOrDefault(era => era.Registration2ID == regId1);
                if (era1 != null)
                {
                    era1.Registration2 = reg2;
                    era1.Registration2ID = regId2;
                }
                else
                {
                    return (false, "allocation not exist!");
                }
            }
            ExamRoomAllocation? era2 = repo.ExamRoomAllocations.FirstOrDefault(era => era.Registration1ID == regId2);
            if (era2 != null)
            {
                era2.Registration1 = reg1;
                era2.Registration2ID = regId1;
            }
            else
            {
                era2 = repo.ExamRoomAllocations.FirstOrDefault(era => era.Registration2ID == regId2);
                if (era2 != null)
                {
                    era2.Registration2 = reg1;
                    era2.Registration2ID = regId1;
                }
                else
                {
                    return (false, "allocation not exist!");
                }
            }
            (bool success1, string msg1)  = CalcStatus(era1);
            (bool success2, string msg2)  = CalcStatus(era2);
            repo.DbContex.SaveChanges();
            return (success1&&success2, msg1+"  "+msg2);
        }

        public (bool success, string msg) AddAllocation(ExamRoomAllocation allocation)
        {
            repo.ExamRoomAllocations.Add(allocation);
            repo.DbContex.SaveChanges();
            return (true, "ok");
        }

        public (bool success, string msg) EmptyAllocations()
        {
            repo.ExamRoomAllocations.RemoveRange(repo.ExamRoomAllocations);
            repo.DbContex.SaveChanges();
            return (true, "ok");
        }

        public MemoryStream GetExportFile()
        {
            List<ExamRoomAllocation> allocations = repo.ExamRoomAllocations.ToList();

            var stream = new MemoryStream();

            //创建一个工作簿
            IWorkbook workbook = new HSSFWorkbook();

            //创建一个 sheet 表
            ISheet sheet = workbook.CreateSheet("排考安排");
            //创建单元格样式
            ICellStyle cellStyle = workbook.CreateCellStyle();
            //创建格式
            IDataFormat dataFormat = workbook.CreateDataFormat();
            //设置为文本格式
            cellStyle.DataFormat = dataFormat.GetFormat("@");

            //创建列名
            IRow rowH = sheet.CreateRow(0);
            rowH.CreateCell(0).SetCellValue("编号");
            rowH.CreateCell(1).SetCellValue("考试名");
            rowH.CreateCell(2).SetCellValue("考场名");
            rowH.CreateCell(3).SetCellValue("考场地址");
            rowH.CreateCell(4).SetCellValue("监考老师1");
            rowH.CreateCell(5).SetCellValue("监考老师2");
            rowH.CreateCell(6).SetCellValue("考试开始时间");
            rowH.CreateCell(7).SetCellValue("考试结束时间");

            // 填入数据
            int index = 1;
            for (int i = 0; i < allocations.Count; i++)
            {
                BuildAllocation(allocations[i]);
                IRow row = sheet.CreateRow(i + 1);
                ExamRoomAllocation temp = allocations[i];
                row.CreateCell(0).SetCellValue(index);
                if(temp.Exam!=null && temp.Exam.ExamName!=null)
                    row.CreateCell(1).SetCellValue(temp.Exam.ExamName);
                if(temp.ExamRoom!=null && temp.ExamRoom.ExamRoomName!=null)
                    row.CreateCell(2).SetCellValue(temp.ExamRoom.ExamRoomName);
                if(temp.ExamRoom!=null && temp.ExamRoom.BuildingName!=null && temp.ExamRoom.RoomNumber!=null)
                    row.CreateCell(3).SetCellValue(temp.ExamRoom.BuildingName + " " + temp.ExamRoom.RoomNumber);
                if(temp.Registration1!=null && temp.Registration1.Name!=null)
                    row.CreateCell(4).SetCellValue(temp.Registration1.Name);
                if(temp.Registration2!=null && temp.Registration2.Name!=null)
                    row.CreateCell(5).SetCellValue(temp.Registration2.Name);
                if(temp.Exam!=null && temp.Exam.ScheduleStartTime!=null)
                    row.CreateCell(6).SetCellValue(temp.Exam.ScheduleStartTime.ToLocalTime().ToString());
                if(temp.Exam!=null && temp.Exam.ScheduleEndTime!=null)
                    row.CreateCell(7).SetCellValue(temp.Exam.ScheduleEndTime.ToLocalTime().ToString());
                index++;
            }

            workbook.Write(stream);

            return stream;
        }
    }
}
